package com.maychat.service.impl;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.maychat.config.AppConfig;
import com.maychat.config.Consts;
import com.maychat.enums.*;
import com.maychat.exception.BusinessException;
import com.maychat.mapper.*;
import com.maychat.pojo.*;
import com.maychat.pojo.extended.ChatSessionComb;
import com.maychat.pojo.extended.GroupInfoWithOwnerName;
import com.maychat.pojo.extended.Message;
import com.maychat.service.ChatSessionUserService;
import com.maychat.service.GroupInfoService;
import com.maychat.service.UserContactService;
import com.maychat.utils.StringTools;
import com.maychat.websocket.ChannelContextUtils;
import com.maychat.websocket.MessageHandler;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.List;

@Slf4j
@Service
public class GroupInfoServiceImpl implements GroupInfoService {

    @Autowired
    private GroupInfoMapper groupInfoMapper;
    @Autowired
    RedisServiceImpl redisService;
    @Autowired
    private UserContactMapper userContactMapper;
    @Autowired
    private AppConfig appConfig;
    @Autowired
    private ChatSessionUserMapper chatSessionUserMapper;
    @Autowired
    private ChannelContextUtils channelContextUtils;
    @Autowired
    private MessageHandler messageHandler;
    @Autowired
    private ChatSessionUserService chatSessionUserService;
    @Autowired
    private ChatMessageMapper chatMessageMapper;
    @Autowired
    private UserContactService userContactService;
    @Autowired
    private UserInfoMapper userInfoMapper;
    @Lazy
    @Autowired
    GroupInfoService groupInfoService;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void saveGroup(GroupInfo groupInfo, MultipartFile avatarSmall, MultipartFile avatarFull) throws BusinessException, IOException {
        if (StringUtils.isBlank(groupInfo.getGroupId())) { // 新增
            log.info("新增群组！！！！");
            String ownerId = groupInfo.getGroupOwnerId();
            GroupInfo queryObj = new GroupInfo();
            queryObj.setGroupOwnerId(ownerId);
            int hasGroupCount = groupInfoMapper.selectGroupInfos(queryObj).size();
            int maxGroupCount = redisService.getSystemOptions().getMaxGroupCount();
            if (hasGroupCount > maxGroupCount)
                throw new BusinessException("最多创建" + maxGroupCount + "个群聊");
            groupInfo.setGroupId(StringTools.generateRandomGroupId());
            groupInfoMapper.insertGroupInfo(groupInfo);
            // 将这个群组添加为自己的联系人
            UserContact userContact = new UserContact(ownerId,
                    groupInfo.getGroupId(), ContactType.GROUP.ordinal(),
                    LocalDateTime.now(), UserContactStatus.FRIEND.ordinal());
            userContactMapper.insertUserContact(userContact);
            // 创建会话
            String sessionId = StringTools.generateGroupSessionId(groupInfo.getGroupId());
            ChatSession chatSession = new ChatSession();
            chatSession.setSessionId(sessionId);
            chatSession.setLastMessage(MessageType.GROUP_CREATE.getInitMessage());
            chatSession.setLastReceiveTime(System.currentTimeMillis());
            chatSessionUserMapper.upsertChatSession(chatSession);
            ChatSessionComb chatSessionComb = new ChatSessionComb();
            chatSessionComb.setSessionId(sessionId);
            chatSessionComb.setUserId(groupInfo.getGroupOwnerId());
            chatSessionComb.setContactId(groupInfo.getGroupId());
            chatSessionComb.setContactName(groupInfo.getGroupName());
            chatSessionUserMapper.insertChatSessionUser(chatSessionComb);

            ChatMessage chatMessage = new ChatMessage();
            chatMessage.setSessionId(sessionId);
            chatMessage.setSendTime(System.currentTimeMillis());
            chatMessage.setContactId(groupInfo.getGroupId());
            chatMessage.setContactType(ContactType.GROUP.ordinal());
            chatMessage.setMessageType(MessageType.GROUP_CREATE.ordinal());
            chatMessage.setMessageContent(MessageType.GROUP_CREATE.getInitMessage());
            chatMessage.setStatus(MessageStatus.SENT.ordinal());
            chatMessageMapper.insertChatMessage(chatMessage);

            redisService.addUserContact(groupInfo.getGroupOwnerId(), groupInfo.getGroupId());
            channelContextUtils.addUser2Group(groupInfo.getGroupOwnerId(), groupInfo.getGroupId());

            chatSessionComb.setLastMessage(MessageType.GROUP_CREATE.getInitMessage());
            chatSessionComb.setLastReceiveTime(System.currentTimeMillis());
            chatSessionComb.setMemberCount(1);

            // 立即发送消息
            Message<ChatSessionComb> msg = new Message<>();
            BeanUtils.copyProperties(chatMessage, msg);
            msg.setExtendedData(chatSessionComb);
            msg.setLastMessage(chatSession.getLastMessage());
            msg.setMemberCount(1);
            log.info("准备好发送的消息：{}", msg);
            messageHandler.sendMsg(msg);
        } else { // 修改
            String operator = groupInfo.getGroupOwnerId();
            GroupInfo queryObj = new GroupInfo();
            queryObj.setGroupId(groupInfo.getGroupId());
            List<GroupInfo> res = groupInfoMapper.selectGroupInfos(queryObj);
            if (res.isEmpty()) throw new BusinessException("期望操作的群聊不存在");
            GroupInfo dbInfo = res.get(0);
            if (!operator.equals(dbInfo.getGroupOwnerId()))
                throw new BusinessException("这不是你的群聊，你没有权限操作");
            groupInfoMapper.updateGroupInfoById(groupInfo);
            // 更新逻辑相关表
            if (dbInfo.getGroupName().equals(groupInfo.getGroupName())) return;

            chatSessionUserService.updateRedundant(groupInfo.getGroupId(), groupInfo.getGroupName());
            ChatSessionUser update = new ChatSessionUser();
            update.setContactId(groupInfo.getGroupId());
            update.setContactName(groupInfo.getGroupName());
            chatSessionUserMapper.updateChatSessionUserByContactId(update);
            // 发送ws消息
            ChatMessage chatMsg = new ChatMessage();
            chatMsg.setContactType(ContactType.GROUP.ordinal());
            chatMsg.setContactId(groupInfo.getGroupId());
            chatMsg.setMessageType(MessageType.CONTACT_NAME_UPDATE.ordinal());

            Message<Object> msg = new Message<>();
            BeanUtils.copyProperties(chatMsg, msg);
            msg.setExtendedData(update);
            messageHandler.sendMsg(msg);
        }
        // 都要处理群头像
        if (avatarFull == null) return;
        String path = appConfig.getProjectFolder() + Consts.FOLDER_FILE_AVATAR;
        File file = new File(path);
        if (!file.exists()) file.mkdirs();
        path += "/" + groupInfo.getGroupId();
        avatarFull.transferTo(new File(path + Consts.IMAGE_SUFFIX));
        if (avatarSmall == null) return;
        avatarSmall.transferTo(new File(path + Consts.IMAGE_SMALL_SUFFIX));
    }

    @Override
    public List<GroupInfo> getMyGroups(String userId) {
        GroupInfo query = new GroupInfo();
        query.setGroupOwnerId(userId);
        query.setStatus(UserStatus.ENABLED.ordinal());
        return groupInfoMapper.selectGroupInfos(query);
    }

    @Override
    public GroupInfo selectGroupInfoById(String groupId) {
        GroupInfo query = new GroupInfo();
        query.setGroupId(groupId);
        List<GroupInfo> res = groupInfoMapper.selectGroupInfos(query);
        if (res.isEmpty()) return null;
        return res.get(0);
    }

    @Override
    public RowsWithTotal<GroupInfoWithOwnerName> selectWithOwnerNameCondByPage(GroupInfo groupInfo, Integer page, Integer pageSize) {
        PageHelper.startPage(page, pageSize);
        Page<GroupInfoWithOwnerName> p = (Page<GroupInfoWithOwnerName>) groupInfoMapper.selectGroupInfoWithOwnerName(groupInfo);
        return RowsWithTotal.of(p);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void dissolveGroup(String groupId, String groupOwnerId) throws BusinessException {
        GroupInfo dbInfo = this.selectGroupInfoById(groupId);
        if (dbInfo == null || !dbInfo.getGroupOwnerId().equals(groupOwnerId))
            throw new BusinessException();
        //
        GroupInfo groupInfo = new GroupInfo();
        groupInfo.setGroupId(groupId);
        groupInfo.setStatus(UserStatus.DISABLED.ordinal());
        groupInfoMapper.updateGroupInfoById(groupInfo);
        //
        UserContact cond = new UserContact();
        cond.setContactId(groupId);
        cond.setContactType(ContactType.GROUP.ordinal());

        UserContact toUpdate = new UserContact();
        toUpdate.setStatus(UserContactStatus.DELETE.ordinal());
        userContactMapper.updateByParam(toUpdate, cond);
        // 移除缓存、更新会话、记录消息、发送解散消息
        long t = System.currentTimeMillis();

        List<UserContact> members = userContactMapper.selectUserContacts(cond);
        for (UserContact member : members) {
            redisService.removeUserContact(member.getUserId(), groupId);
        }

        String sessionId = StringTools.generateGroupSessionId(groupId);
        String dissolveMsg = MessageType.DISSOLVE_GROUP.getInitMessage();
        ChatSession chatSession = new ChatSession();
        chatSession.setLastMessage(dissolveMsg);
        chatSession.setSessionId(sessionId);
        chatSession.setLastReceiveTime(t);
        chatSessionUserMapper.updateChatSessionBySessionId(chatSession);

        Message<Object> chatMessage = new Message<>();
        chatMessage.setSessionId(sessionId);
        chatMessage.setSendTime(t);
        chatMessage.setContactType(ContactType.GROUP.ordinal());
        chatMessage.setStatus(MessageStatus.SENT.ordinal());
        chatMessage.setMessageType(MessageType.DISSOLVE_GROUP.ordinal());
        chatMessage.setContactId(groupId);
        chatMessage.setMessageContent(dissolveMsg);
        chatMessageMapper.insertChatMessage(chatMessage);

        messageHandler.sendMsg(chatMessage);
    }

    @Override
    public void changeGroupMember(String userId, String groupId, List<String> ids, Integer action) throws BusinessException {
        GroupInfo query = new GroupInfo();
        query.setGroupId(groupId);
        query.setGroupOwnerId(userId);
        List<GroupInfo> res = groupInfoMapper.selectGroupInfos(query);
        if (res.isEmpty()) throw new BusinessException();
        for (String id : ids) {
            if (action == 0) {
                userContactService.addContact(id, userId, groupId, ContactType.GROUP.ordinal(), null);
            } else {
                groupInfoService.leaveGroup(id, groupId, MessageType.FORCED_LEAVE_GROUP);
            }
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void leaveGroup(String userId, String groupId, MessageType type) throws BusinessException {
        GroupInfo query = new GroupInfo();
        query.setGroupId(groupId);
        List<GroupInfo> res = groupInfoMapper.selectGroupInfos(query);
        if (res.isEmpty()) throw new BusinessException();
        GroupInfo dbInfo = res.get(0);
        if (userId.equals(dbInfo.getGroupOwnerId()))
            throw new BusinessException("神金，群主把自己踢出群?");
        Integer count = userContactMapper.deleteByUIdAndCId(userId, groupId);
        if (count == 0) throw new BusinessException();
        UserInfo userInfo = userInfoMapper.selectUserInfoById(userId);
        String sessionId = StringTools.generateGroupSessionId(groupId);
        long t = System.currentTimeMillis();
        String msgStr = userInfo.getNickName() + type.getInitMessage();
        ChatSession chatSession = new ChatSession();
        chatSession.setSessionId(sessionId);
        chatSession.setLastMessage(msgStr);
        chatSession.setLastReceiveTime(t);
        chatSessionUserMapper.updateChatSessionBySessionId(chatSession);

        Message<Object> msg = new Message<>();
        msg.setSessionId(sessionId);
        msg.setSendTime(t);
        msg.setContactType(ContactType.GROUP.ordinal());
        msg.setStatus(MessageStatus.SENT.ordinal());
        msg.setMessageType(type.ordinal());
        msg.setContactId(groupId);
        msg.setMessageContent(msgStr);
        chatMessageMapper.insertChatMessage(msg);

        Integer memberCount = this.selectGroupMemberCount(groupId);
        msg.setMemberCount(memberCount);
        msg.setExtendedData(userId);
        messageHandler.sendMsg(msg);
    }

    @Override
    public Integer selectGroupMemberCount(String groupId) {
        UserContact query = new UserContact();
        query.setContactId(groupId);
        query.setStatus(UserContactStatus.FRIEND.ordinal());
        return userContactMapper.selectUserContactCount(query);
    }

}
